class_name Player extends CharacterBody2D


# Movement Constants
const GRAVITY = 650.0
const WALK_FORCE = 600
const WALK_MIN = 10
const WALK_MAX = 200
const STOP_FORCE = 1300
const STOP_COEFF = 0.65
const MAX_JUMP = 0.105#0.65
const JUMP_VEL = 220#280
const MAX_AIR = 0.1 # Due to physics, character is always in the air. This is a tolerance

# Variables
# Movement	
var jumping = false
var can_jump = true
var falling = false
# +++ 开始 1
@export var attacking = false # player is attacking
var can_attack = true
# +++ 结束
var air_time = 100
var jump_time
# Input
var walk_left
var walk_right
var walk_up
var walk_down
var jump
var attack
# Combat
@export var vulnerable = true
# +++ 开始 2
var sword_hit = preload("res://scenes/sword_hit.tscn")
var strong_hit = preload("res://scenes/strong_slash.tscn")
@export var create_sword = false
var attack_spot
var aspd
# +++ 结束
# Spritework
var top_anim
var bot_anim
var top_sprite
var bot_sprite
var effects
# +++ 开始 3
@export var need_synchro = false
# +++ 结束
var dust = preload("res://scenes/dust.tscn")
var landed = false
var stopped = false
# Death
var smoke_effects = preload("res://scenes/smoke_effects.tscn")
var dead = false

# Get the gravity from the project settings to be synced with RigidBody nodes.


var controller

# test code 测试攻击速度
#var time_begin = 0
# test code end

func _ready():
	controller = get_node("/root/Controller")
	# +++ 开始 4
	aspd = get_node("/root/Progress").checks["AttackSpeedUpgrade"]
	attack_spot = get_node("TopBody/AttackSpot")
	# +++ 结束
	controller.cam_target = self
	jump_time = get_node("Jump")
	jump_time.set_wait_time(MAX_JUMP)
	effects = get_node("Effects")
	top_anim = get_node("TopAnim")
	bot_anim = get_node("LowerAnim")
	top_sprite = get_node("TopBody")
	bot_sprite = get_node("LowerBody")	

func _physics_process(delta):
	if (bot_anim.get_current_animation() != "victory" and effects.get_current_animation() != "involnerable"):
		effects.play("upnone")
	
	if (controller.cutscene):
		walk_left = false
		walk_right = false
		walk_up = false
		walk_down = false
		jump = false
		attack = false
	else:
		walk_left = Input.is_action_pressed("ui_left")
		walk_right = Input.is_action_pressed("ui_right")
		walk_up = Input.is_action_pressed("ui_up")
		walk_down = Input.is_action_pressed("ui_down")
		jump = Input.is_action_pressed("jump")
		attack = Input.is_action_pressed("attack")
	_movement(delta)

#   测试子弹	
#	if (Input.is_action_just_released("attack")):
#		var map = controller.current_map
#		var bullet = load("res://scenes/bullet.tscn")
#		var instance = bullet.instantiate()
#		map.add_child(instance)
#		instance.global_position = global_position - Vector2(0,96)

#   测试攻击速度升级
#	if (Input.is_action_just_released("ui_select")):
#		print("attack upgrade")
#		aspd = true

#   测试攻击速度升级
#	if (Input.is_action_just_released("ui_select")):
#		print("attack upgrade")
#		aspd = true

#    测试对话
#	if (Input.is_action_just_released("attack")):
#		var text_list:Array[String] = ["story1","story2","story3"]
#		print('showtext')
#		controller.begin_cutscene()
#		controller.show_text(text_list)
	

func _movement(delta):
	# gravity
	var force = Vector2(0,GRAVITY)
	
	# stop by default, inertia
	var stop = true
#	print("V1:" + str(velocity.x) + " F:" + str(force.x))
	# Sideways movement
	if (walk_left and not walk_right):
		if (velocity.x<=WALK_MIN and velocity.x > -WALK_MAX):
			force.x-=WALK_FORCE
			stop = false
			stopped = false
			if (bot_anim.get_current_animation() != "run" and !jumping && !falling):
				bot_anim.play("run")
			if (top_anim.get_current_animation() != "run" and !jumping && !falling):
				top_anim.play("run")
		else:
			force.x = -WALK_FORCE * STOP_COEFF
	elif (walk_right and not walk_left):
		if (velocity.x>=-WALK_MIN and velocity.x < WALK_MAX):
			force.x+=WALK_FORCE
			stop = false
			stopped = false
			if (bot_anim.get_current_animation() != "run" and !jumping && !falling):
				bot_anim.play("run")
			if (top_anim.get_current_animation() != "run" and !jumping && !falling ):
				top_anim.play("run")
		else:
			force.x = WALK_FORCE * STOP_COEFF
	
	# if the player got no movement, he'll slow down with inertia.
	if (stop):
		stop(delta)
		
#	print("V2:" + str(velocity.x) + " F:" + str(force.x))
	# calculate motion
	velocity += force * delta
	var isOnFloor = is_on_floor()
	move_and_slide()
	
	# print("F:"+str(falling)+" J:"+str(jumping))
	# because the first move would stop if there's a collision, we recalculate the movement to slide along the colliding object.
	if not isOnFloor and is_on_floor():
		#if angle to the "up" vectors is < angle tolerance
		#char is on floor
		falling = false
		if (not landed):
			create_dust("land")
			play_sfx("step")
			landed = true

	if is_on_floor():
		air_time=0
	else:
		air_time+=delta
	
	if (jumping and velocity.y>=0):
		falling = true
		jumping=false
		
	if (velocity.y > 0 and air_time > MAX_AIR):
		falling = true
	
	if (velocity.y < 0 and bot_anim.get_current_animation() != "jump"):
		bot_anim.play("jump")
		if (!attacking):
			top_anim.play("jump")

	if (falling and bot_anim.get_current_animation() != "fall"):
		bot_anim.play("fall")
		if (!attacking):
			top_anim.play("fall")

	# Manage jumping
	if (!jump):
		can_jump = true
	elif (not jumping and can_jump and jump and not falling):
		can_jump = false
		if (!is_attacking()):
			top_anim.play("jump")
		bot_anim.play("jump")
		create_dust("jump")
		play_sfx("jump")
		jumping=true
		jump_time.start()
		velocity.y = -JUMP_VEL
		
	#+++开始 5
	# Manage attack
	if (!attack):
		can_attack = true
	elif (can_attack and attack && !attacking):
		can_attack = false
		if (strong_hit and walk_down):
			strong_attack()
		else:
			do_attack()

	# Create attack damage hit
	if (create_sword):
		create_sword = false
		#attack_spot.add_child(sword_hit.instance())
		attack_spot.add_child(sword_hit.instantiate())

	# Synchronize both halfs animation
	if (is_attacking() and need_synchro):		
		top_anim.play(bot_anim.get_current_animation())
		#top_anim.seek(bot_anim.get_pos(),true)
		top_anim.seek(bot_anim.current_animation_position,true)
	need_synchro = false
	#+++结束
	
	if not is_zero_approx(velocity.x):
		if velocity.x > 0.0:
			top_sprite.scale.x = 1.0
			bot_sprite.scale.x = 1.0
		else:
			top_sprite.scale.x = -1.0
			bot_sprite.scale.x = -1.0

	# Dust states
	if (landed and (jumping or falling)):
		landed = false
	
	#+++开始 6
	# Make sure attack fixes
	if (attacking and !is_attacking()):
		attacking = false
	#+++结束
		
func stop(delta):
	var vsign = sign(velocity.x)
	var vx = abs(velocity.x)
	vx -= STOP_FORCE * delta
	if (vx<0):
		vx=0
		if (bot_anim.get_current_animation() != "idle" and bot_anim.get_current_animation() != "victory" and !jumping and !falling):
			if (not stopped and not jumping and not falling):
				create_dust("brake")
				stopped = true
			bot_anim.play("idle")
			print(top_anim.get_current_animation())
			if (!is_attacking() and top_anim.get_current_animation() != "victory"):
				top_anim.play("idle")
	velocity.x=vx*vsign

#+++开始 7
func do_attack():
	# test code	测试攻击速度
#	var time = (Time.get_ticks_usec() - time_begin) / 1000000.0
#	print("attack Interval " + str(time))
#	time_begin = Time.get_ticks_usec()
	# test code end
	
	attacking = true
	if (top_anim.get_current_animation() != "attack" and top_anim.get_current_animation() != "attack2"):
		top_anim.play("attack")
	elif (top_anim.get_current_animation() == "attack"):
		top_anim.play("attack2")
	elif (top_anim.get_current_animation() == "attack2"):
		top_anim.play("attack")

func strong_attack():
	attacking = true
	attack_spot.add_child(strong_hit.instantiate())
	top_anim.play("strong_attack")

func is_attacking():
	if (top_anim.get_current_animation() == "attack" or
		top_anim.get_current_animation() == "attack2" or
		top_anim.get_current_animation() == "strong_attack"):
		return true
	else:
		return false

func slow_attack():
	if (not aspd):
		attacking = false

func fast_attack():
	if (aspd):
		attacking = false
#+++结束

func create_dust(type):
	var map = controller.current_map
	var instance = dust.instantiate()
	instance.play(type)
	map.add_child(instance)
	instance.global_position = global_position + Vector2(0,32)
	instance.scale = Vector2(top_sprite.scale.x,1)
	
func death():
	dead = true
	var map = controller.current_map
	var instance = smoke_effects.instantiate()
	map.add_child(instance)
	get_node("/root/SoundManager").play_sfx("smoke",true)
	instance.play()
	instance.global_position = global_position - Vector2(0,16)
	instance.scale = Vector2(top_sprite.scale.x,1)
	hide()
	top_anim.stop()
	bot_anim.stop()

func play_sfx(type):
	get_node("SimplePlayer/"+type).play()
	
func _on_Jump_timeout():
	if (jump):
		velocity.y = -JUMP_VEL


func _on_Hitbox_body_enter(body):
	if (body.getDamageType() == "hurtful"):
		# Knockback some time maybe
		if (not dead and vulnerable):
			vulnerable = false
			effects.play("involnerable")
			controller.life_down()
	elif (body.getDamageType() == "killer"):
		if (not dead):
			controller.life_down()
			controller.life_down()
